package org.junwei.common.util;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cglib.beans.BeanCopier;
import org.springframework.cglib.beans.BeanMap;

public class ObjectUtils extends org.apache.commons.lang3.ObjectUtils{
	
	private static final Logger logger = LoggerFactory.getLogger(ObjectUtils.class);
	
	/**
	 * 缓存BeanCopier实例
	 */
	private static final Map<String, BeanCopier> beanCopierCache = new ConcurrentHashMap<>();

	private ObjectUtils() {}

	/**
     * 获取缓存中的BeanCopier对象。如果没有新建一个并存储
     * @param sourceClass
     * @param targetClass
     * @return
     */
    private static BeanCopier getBeanCopier(Class<?> sourceClass, Class<?> targetClass) {
    	String beanKey =  sourceClass.toString() + targetClass.toString();
        BeanCopier copier = null;
        if (!beanCopierCache.containsKey(beanKey)) {
            copier = BeanCopier.create(sourceClass, targetClass, false);
            beanCopierCache.put(beanKey, copier);
        } else {
            copier = beanCopierCache.get(beanKey);
        }
        return copier;
    }
    
	/**
	 * 对象转化为Map
	 * @param obj
	 * @param ignoreNull null值是否存入最终的map中
	 * @return Map<String, String>
	 * @throws IllegalAccessException
	 */
	public static Map<String, String> objectToMap(Object obj, boolean ignoreNull) throws IllegalAccessException {
		
		Map<String, String> map = new HashMap<>();
		if(obj == null)
			return map;
		
		for (Field field : obj.getClass().getDeclaredFields()) {
			field.setAccessible(true);
			String fieldName = field.getName();
			Object value = field.get(obj);
			if (value == null && ignoreNull == true) {
				continue;
			}
			
			if(field.getType() == Date.class) {
				map.put(fieldName, DateUtils.formatDate((Date) value, "yyyy-MM-dd HH:mm:ss"));
				continue;
			}
			map.put(fieldName, value == null ? null : value.toString());
		}
		return map;
	}
	
	/**
     * <xmp>Map<String, Object>转Map<String, String></xmp>
     * @param sourceMap 需要被转换的map
     */
	public static Map<String,String> convert(Map<String, Object> sourceMap) {
		if(sourceMap == null)
			throw new IllegalArgumentException("参数为null");
		
		Map<String, String> result = new HashMap<>(sourceMap.size());
		Set<String> keySet = sourceMap.keySet();
		for (String key : keySet) {
			Object object = sourceMap.get(key);
			if (object != null) {
				if (object instanceof Date) {
					sourceMap.put(key, DateUtils.formatDateTime((Date) object));
					continue;
				}
				result.put(key, object.toString());
			}
		}
		return result;
	}
	
	/**
     * Map转成实体对象
     * @param map map实体对象包含属性
     * @param clazz 实体对象类型
     * @return
     */
    public static <T> T map2Object(Map<String, Object> map, Class<T> clazz) {
        if (map == null) {
            return null;
        }
        T t = null;
        try {
            t = clazz.newInstance();

            Field[] fields = t.getClass().getDeclaredFields();
            for (Field field : fields) {
                int mod = field.getModifiers();
                if (Modifier.isStatic(mod) || Modifier.isFinal(mod)) {
                    continue;
                }
                field.setAccessible(true);
                field.set(t, map.get(field.getName()));
            }
        } catch (Exception e) {
            e.printStackTrace();
        } 
        return t;
    }

    /**
     * map对象转换为javabean对象(null值会复制)
     * @param map 
     * @param bean
     */
	public static <T> T convert(Map<String, Object> map, T bean) {  
	    BeanMap beanMap = BeanMap.create(bean);  
	    beanMap.putAll(map); 
	    return bean;
	}  
	
	/**
	 * javabean转map
	 * @param bean
	 * @param ignoreNull true忽略javabean中null值属性
	 * @return
	 */
	public static Map<String, Object> convert(Object bean, boolean ignoreNull) {  
	    Map<String, Object> map = new HashMap<>(16);
	    if (bean != null) {  
	        BeanMap beanMap = BeanMap.create(bean);  
	        for (Object key : beanMap.keySet()) { 
	        	if (beanMap.get(key) == null && ignoreNull == true) continue;
	        	if (beanMap.get(key) != null && beanMap.get(key) instanceof Date) {
	        		map.put(key+"", DateUtils.formatDateTime((Date) beanMap.get(key)));
	        		continue;
	        	}
	            map.put(key+"", beanMap.get(key)); 
	        }
	    }  
	    return map;  
	} 
	
	/**
	 * javabean转map
	 * @param beans
	 * @param ignoreNull ignoreNull true忽略javabean中null值属性
	 * @return
	 */
	public static List<Map<String, Object>> convert(List<?> beans, boolean ignoreNull) {  
		if(beans == null || beans.size() == 0)
			return new ArrayList<>();
		
		List<Map<String, Object>> list = new ArrayList<>(beans.size());
		for (Object bean : beans) {
			list.add(convert(bean, ignoreNull));
		}
		return list;  
	} 

    /**
     * 对象转换(浅复制，null值会复制，名称类型都相同才复制)，不适用于集合对象
     * @param source
     * @param target
     */
    public static void convert(Object source, Object target) {
        BeanCopier copier = getBeanCopier(source.getClass(), target.getClass());
        copier.copy(source, target, null);
    }
    
    /**
     * 对象转换(浅复制，null值会复制，名称类型都相同才复制)，不适用于集合对象
     * @param source 源对象
     * @param targetClass 目标对象
     * @return
     * @throws Exception 
     */
    public static <T> T convert(Object source, Class<T> targetClass) throws Exception {
        T t = null;
        try {
            t = targetClass.newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
        	logger.error(targetClass + "实例化异常", e);
            throw e;
        }
        convert(source, t);
        return t;
    }

    /**
     * 对象列表转换（(浅复制，null值会复制，名称类型都相同才复制)）
     * @param sourceList
     * @param targetClass 不能是集合对象
     * @return
     */
    public static <T> List<T> convertList(List<?> sourceList, Class<T> targetClass) {
        if (sourceList == null || sourceList.size() == 0) {
            return Collections.emptyList();
        }
        List<T> resultList = new ArrayList<>(sourceList.size());
        for (Object o : sourceList) {
            T t = null;
            try {
            	// TODO 反射优化考虑使用reflectasm框架
                t = targetClass.newInstance();
                convert(o, t);
                resultList.add(t);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        return resultList;
    }
}
